package resources;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class MotorDoJogo {
	/** Representa o Jogador X. */
	public static final char JOGADOR_X = 'X';
	/** Representa o Jogador O. */
	public static final char JOGADOR_O = 'O';
	/** Representa um espaco vazio no tabuleiro. */
	public static final char FACE_ABAIXADA = 'A';
	public static final char FACE_LEVANTADA = 'L';
	public static final char JOGADOR_VAZIO = ' ';

	/** Status: Aguarde a vez de jogar. */
	public static final String STATUS_AGUARDE = "aguarde";
	/** Status: E' a vez de jogar. */
	public static final String STATUS_JOGUE = "jogue";
	/** Status: Jogador ganhou. */
	public static final String STATUS_GANHOU = "ganhou";
	/** Status: Jogador perdeu. */
	public static final String STATUS_PERDEU = "perdeu";
	/** Status: Houve empate. */
	public static final String STATUS_EMPATE = "empate";
	/** Status: Outro jogador abandonou a partida. */
	public static final String STATUS_WO = "abandonou";

	private Jogador jogadorUm;
	private Jogador jogadorDois;

	public Jogador getJogadorUm() {
		return jogadorUm;
	}

	public void setJogadorUm(Jogador jogadorUm) {
		this.jogadorUm = jogadorUm;
	}

	public Jogador getJogadorDois() {
		return jogadorDois;
	}

	public void setJogadorDois(Jogador jogadorDois) {
		this.jogadorDois = jogadorDois;
	}

	/** Construtor default. */
	public MotorDoJogo() {
		reorganiza();
		this.jogadorUm = Jogador();

	}

	/**
	 * Retorna qual o oponente do jogador.
	 * 
	 * @param jogador
	 *            Jogador a ser retornado seu oponente
	 * @return Oponente do jogador, ou @ref JOGADOR_VAZIO se jogador nao e'
	 *         valido.
	 */
	public static char getOponente(char jogador) {
		switch (jogador) {
		case JOGADOR_X:
			return JOGADOR_O;
		case JOGADOR_O:
			return JOGADOR_X;
		default:
			return JOGADOR_VAZIO;
		}
	}

	// /**
	// * Retorna uma posicao no tabuleiro.
	// * @param pos Posicao (de 0 a 8)
	// * @return Jogador marcado na posicao ou @ref JOGADOR_VAZIO se nao houver.
	// */
	// public char getPosicao(int pos) {
	// return tabuleiro[pos];
	// }
	//
	// /**
	// * Altera uma posicao no tabuleiro.
	// * @param pos Posicao (de 0 a 8)
	// * @param jogador Jogador a ser marcado na posicao (@ref JOGADOR_X,
	// * @ref JOGADOR_O ou @ref JOGADOR_VAZIO)
	// */
	// public void setPosicao(int pos, char jogador) {
	// if (jogador == JOGADOR_O || jogador == JOGADOR_X) {
	// tabuleiro[pos] = jogador;
	// }
	// }

	public void escolheFace(Face face) {
		face.setEscolhido(true);
	}

	public void reorganiza() {

		for (Face face : faces) {
			face.setStatus(Face.LEVANTADO);
			face.setEscolhido(false);
		}
	}

	// /**
	// * Copia um vetor para o tabuleiro.
	// * @param from Vetor origem, com a representacao de um tabuleiro
	// * (9 posicoes).
	// */
	// public void copiarTabuleiro(char[] from) {
	// if (from != null && from.length == tabuleiro.length) {
	// for (int pos = 0; pos < tabuleiro.length; pos++) {
	// tabuleiro[pos] = from[pos];
	// }
	// }
	// }
	//
	/**
	 * Verifica se o jogo terminou (um jogador ganhou ou deu empate).
	 * 
	 * @return True se o jogo terminou, false se nao.
	 */
	public boolean isGameOver() {
		return (isCheio() || isGanhador(JOGADOR_X) || isGanhador(JOGADOR_O));
	}

	/**
	 * Retorna o jogador ganhador.
	 * 
	 * @return Jogador que ganhou (@ref JOGADOR_X ou @ref JOGADOR_O), ou @ref
	 *         JOGADOR_VAZIO se nenhum jogador ganhou.
	 */
	public char getGanhador() {
		int trio[] = getTrioGanhador();

		if (trio == null || trio.length < 3) {
			return JOGADOR_VAZIO;
		} else {
			return tabuleiro[trio[0]];
		}
	}

	/**
	 * Retorna as tres posicoes das jogadas do ganhador.
	 * 
	 * @return Vetor com as tres posicoes da jogada ganhadora, ou null se nenhum
	 *         jogador ganhou.
	 */
	public int[] getTrioGanhador() {
		int retorno[] = null;
		int p[] = new int[3];
		char j[] = new char[3];

		for (int pos = 0; pos < TRIOS.length; pos++) {
			for (int p1 = 0; p1 < 3; p1++) {
				p[p1] = TRIOS[pos][p1];
				j[p1] = tabuleiro[p[p1]];
			}

			if (j[0] != JOGADOR_VAZIO && j[0] == j[1] && j[1] == j[2]) {
				retorno = new int[3];
				for (int p1 = 0; p1 < 3; p1++) {
					retorno[p1] = p[p1];
				}
			}
		}
		return retorno;
	}

	/**
	 * Verifica se um jogador ganhou.
	 * 
	 * @param jogador
	 *            Jogador a ser verificado (@ref JOGADOR_X ou
	 * @ref JOGADOR_O)
	 * @return True se o jogador indicado ganhou, false se nao.
	 */
	public boolean isGanhador(char jogador) {
		return (getGanhador() == jogador);
	}

	/**
	 * Verifica se houve empate.
	 * 
	 * @return True se houve empate, false se nao.
	 */
	public boolean isEmpate() {
		return (isCheio() && getGanhador() == JOGADOR_VAZIO);
	}

	/**
	 * Verifica se o tabuleiro esta' vazio (todas as posicoes marcadas com @ref
	 * JOGADOR_VAZIO).
	 * 
	 * @return True se tabuleiro esta' vazio, false se nao.
	 */
	public boolean isVazio() {
		return isVazio(0, tabuleiro.length - 1);
	}

	/**
	 * Retorna a proxima jogada para um jogador. Este metodo contem a "AI"
	 * necessaria para um robot de Jogo da Velha. (Baseado na "Jogada Perfeita"
	 * descrita em http://pt.wikipedia.org/wiki/Jogo_da_velha#Jogada_perfeita).
	 * 
	 * @param jogador
	 *            Jogador a ser verificada a proxima jogada (@ref JOGADOR_X ou @ref
	 *            JOGADOR_O)
	 * @return Posicao no tabuleiro onde deve ser a proxima jogada, ou -1 se nao
	 *         ha' mais posicoes disponiveis no tabuleiro.
	 */
	public int getJogada(char jogador) {
		int jogada = -1;

		/* Jogada Perfeita: passo 1 */
		jogada = getJogadaAtaque(jogador);
		if (jogada >= 0)
			return jogada;

		/* Jogada Perfeita: passo 2 */
		if (new Random().nextInt(10) >= (10 - nivel)) {
			jogada = getJogadaDefesa(jogador);
			if (jogada >= 0)
				return jogada;
		}

		/* Jogada Perfeita: passo 3 */
		/*
		 * 50%, para que o robot nao tente sempre iniciar pelos cantos, ficando
		 * o jogo monotono
		 */
		if (isVazio() && new Random().nextBoolean()) {
			jogada = getJogadaCanto(jogador);
			if (jogada >= 0)
				return jogada;
		}
		jogada = getJogadaAtaqueTriangulo(jogador);
		if (jogada >= 0)
			return jogada;

		/* Jogada Perfeita: passo 4 */
		if (new Random().nextInt(10) >= (10 - nivel)) {
			jogada = getJogadaDefesaTriangulo(jogador);
			if (jogada >= 0)
				return jogada;
		}

		/* Jogada Perfeita: passo 5 */
		if (tabuleiro[4] == JOGADOR_VAZIO) {
			jogada = 4;
			return jogada;
		}

		/* Jogada Perfeita: passo 6 */
		jogada = getJogadaCanto(jogador);
		if (jogada >= 0)
			return jogada;

		/* borda: ultima opcao */
		jogada = getJogadaBorda(jogador);
		if (jogada >= 0)
			return jogada;

		return -1;
	}

	/**
	 * Verifica se o trecho especificado do tabuleiro esta' vazio (as posicoes
	 * marcadas com @ref JOGADOR_VAZIO).
	 * 
	 * @param start
	 *            Posicao inicial a analisar (0 a 8)
	 * @param end
	 *            Posicao final a analisar (0 a 8)
	 * @return True se trecho do tabuleiro esta' vazio, false se nao.
	 */
	private boolean isVazio(int start, int end) {
		if (start > end) {
			int temp = start;
			start = end;
			end = temp;
		}

		if (start < 0)
			start = 0;
		if (end >= tabuleiro.length)
			end = tabuleiro.length - 1;

		for (int pos = start; pos <= end; pos++) {
			if (tabuleiro[pos] != JOGADOR_VAZIO)
				return false;
		}
		return true;
	}

	/**
	 * Verifica se o tabuleiro esta' cheio (nenhuma posicao marcada com @ref
	 * JOGADOR_VAZIO).
	 * 
	 * @return True se tabuleiro esta' cheio, false se nao.
	 */
	private boolean isCheio() {
		for (int pos = 0; pos < tabuleiro.length; pos++) {
			if (tabuleiro[pos] == JOGADOR_VAZIO)
				return false;
		}
		return true;
	}

}
